package han.cirno.corrupt.components.monet

import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color
import java.io.Serializable

internal data class HalfMonetPalette(
    val primary: Color,
    val onPrimary: Color,
    val primaryContainer: Color,
    val onPrimaryContainer: Color,
    val secondary: Color,
    val onSecondary: Color,
    val secondaryContainer: Color,
    val onSecondaryContainer: Color,
    val tertiary: Color,
    val onTertiary: Color,
    val tertiaryContainer: Color,
    val onTertiaryContainer: Color,
    val error: Color,
    val onError: Color,
    val errorContainer: Color,
    val onErrorContainer: Color,
    val background: Color,
    val onBackground: Color,
    val surface: Color,
    val onSurface: Color,
    val surfaceVariant: Color,
    val onSurfaceVariant: Color,
    val outline: Color,
    val outlineVariant: Color,
    val scrim: Color,
    val inverseSurface: Color,
    val inverseOnSurface: Color,
    val inversePrimary: Color,
    val surfaceDim: Color,
    val surfaceBright: Color,
    val surfaceContainerLowest: Color,
    val surfaceContainerLow: Color,
    val surfaceContainer: Color,
    val surfaceContainerHigh: Color,
    val surfaceContainerHighest: Color,
)

interface MonetPalette{
    val lightScheme:ColorScheme
    val darkScheme:ColorScheme

    val legacyPalette:MonetPalette
        get()=
            MonetPaletteSystem(
                lightScheme.toLegacy(),
                darkScheme.toLegacy()
            )
}

class MonetPaletteSystem(
    override val lightScheme: ColorScheme,
    override val darkScheme: ColorScheme
):MonetPalette

data class MonetPaletteImpl(
    val primaryLight: Color,
    val onPrimaryLight: Color,
    val primaryContainerLight: Color,
    val onPrimaryContainerLight: Color,
    val secondaryLight: Color,
    val onSecondaryLight: Color,
    val secondaryContainerLight: Color,
    val onSecondaryContainerLight: Color,
    val tertiaryLight: Color,
    val onTertiaryLight: Color,
    val tertiaryContainerLight: Color,
    val onTertiaryContainerLight: Color,
    val errorLight: Color,
    val onErrorLight: Color,
    val errorContainerLight: Color,
    val onErrorContainerLight: Color,
    val backgroundLight: Color,
    val onBackgroundLight: Color,
    val surfaceLight: Color,
    val onSurfaceLight: Color,
    val surfaceVariantLight: Color,
    val onSurfaceVariantLight: Color,
    val outlineLight: Color,
    val outlineVariantLight: Color,
    val scrimLight: Color,
    val inverseSurfaceLight: Color,
    val inverseOnSurfaceLight: Color,
    val inversePrimaryLight: Color,
    val surfaceDimLight: Color,
    val surfaceBrightLight: Color,
    val surfaceContainerLowestLight: Color,
    val surfaceContainerLowLight: Color,
    val surfaceContainerLight: Color,
    val surfaceContainerHighLight: Color,
    val surfaceContainerHighestLight: Color,
    val primaryDark: Color,
    val onPrimaryDark: Color,
    val primaryContainerDark: Color,
    val onPrimaryContainerDark: Color,
    val secondaryDark: Color,
    val onSecondaryDark: Color,
    val secondaryContainerDark: Color,
    val onSecondaryContainerDark: Color,
    val tertiaryDark: Color,
    val onTertiaryDark: Color,
    val tertiaryContainerDark: Color,
    val onTertiaryContainerDark: Color,
    val errorDark: Color,
    val onErrorDark: Color,
    val errorContainerDark: Color,
    val onErrorContainerDark: Color,
    val backgroundDark: Color,
    val onBackgroundDark: Color,
    val surfaceDark: Color,
    val onSurfaceDark: Color,
    val surfaceVariantDark: Color,
    val onSurfaceVariantDark: Color,
    val outlineDark: Color,
    val outlineVariantDark: Color,
    val scrimDark: Color,
    val inverseSurfaceDark: Color,
    val inverseOnSurfaceDark: Color,
    val inversePrimaryDark: Color,
    val surfaceDimDark: Color,
    val surfaceBrightDark: Color,
    val surfaceContainerLowestDark: Color,
    val surfaceContainerLowDark: Color,
    val surfaceContainerDark: Color,
    val surfaceContainerHighDark: Color,
    val surfaceContainerHighestDark: Color,
):Serializable,MonetPalette{
    internal constructor(lightPalette: HalfMonetPalette,darkPalette: HalfMonetPalette):this(
        primaryLight=lightPalette.primary,
        onPrimaryLight=lightPalette.onPrimary,
        primaryContainerLight=lightPalette.primaryContainer,
        onPrimaryContainerLight=lightPalette.onPrimaryContainer,
        secondaryLight=lightPalette.secondary,
        onSecondaryLight=lightPalette.onSecondary,
        secondaryContainerLight=lightPalette.secondaryContainer,
        onSecondaryContainerLight=lightPalette.onSecondaryContainer,
        tertiaryLight=lightPalette.tertiary,
        onTertiaryLight=lightPalette.onTertiary,
        tertiaryContainerLight=lightPalette.tertiaryContainer,
        onTertiaryContainerLight=lightPalette.onTertiaryContainer,
        errorLight=lightPalette.error,
        onErrorLight=lightPalette.onError,
        errorContainerLight=lightPalette.errorContainer,
        onErrorContainerLight=lightPalette.onErrorContainer,
        backgroundLight=lightPalette.background,
        onBackgroundLight=lightPalette.onBackground,
        surfaceLight=lightPalette.surface,
        onSurfaceLight=lightPalette.onSurface,
        surfaceVariantLight=lightPalette.surfaceVariant,
        onSurfaceVariantLight=lightPalette.onSurfaceVariant,
        outlineLight=lightPalette.outline,
        outlineVariantLight=lightPalette.outlineVariant,
        scrimLight=lightPalette.scrim,
        inverseSurfaceLight=lightPalette.inverseSurface,
        inverseOnSurfaceLight=lightPalette.inverseOnSurface,
        inversePrimaryLight=lightPalette.inversePrimary,
        surfaceDimLight=lightPalette.surfaceDim,
        surfaceBrightLight=lightPalette.surfaceBright,
        surfaceContainerLowestLight=lightPalette.surfaceContainerLowest,
        surfaceContainerLowLight=lightPalette.surfaceContainerLow,
        surfaceContainerLight=lightPalette.surfaceContainer,
        surfaceContainerHighLight=lightPalette.surfaceContainerHigh,
        surfaceContainerHighestLight=lightPalette.surfaceContainerHighest,
        primaryDark=darkPalette.primary,
        onPrimaryDark=darkPalette.onPrimary,
        primaryContainerDark=darkPalette.primaryContainer,
        onPrimaryContainerDark=darkPalette.onPrimaryContainer,
        secondaryDark=darkPalette.secondary,
        onSecondaryDark=darkPalette.onSecondary,
        secondaryContainerDark=darkPalette.secondaryContainer,
        onSecondaryContainerDark=darkPalette.onSecondaryContainer,
        tertiaryDark=darkPalette.tertiary,
        onTertiaryDark=darkPalette.onTertiary,
        tertiaryContainerDark=darkPalette.tertiaryContainer,
        onTertiaryContainerDark=darkPalette.onTertiaryContainer,
        errorDark=darkPalette.error,
        onErrorDark=darkPalette.onError,
        errorContainerDark=darkPalette.errorContainer,
        onErrorContainerDark=darkPalette.onErrorContainer,
        backgroundDark=darkPalette.background,
        onBackgroundDark=darkPalette.onBackground,
        surfaceDark=darkPalette.surface,
        onSurfaceDark=darkPalette.onSurface,
        surfaceVariantDark=darkPalette.surfaceVariant,
        onSurfaceVariantDark=darkPalette.onSurfaceVariant,
        outlineDark=darkPalette.outline,
        outlineVariantDark=darkPalette.outlineVariant,
        scrimDark=darkPalette.scrim,
        inverseSurfaceDark=darkPalette.inverseSurface,
        inverseOnSurfaceDark=darkPalette.inverseOnSurface,
        inversePrimaryDark=darkPalette.inversePrimary,
        surfaceDimDark=darkPalette.surfaceDim,
        surfaceBrightDark=darkPalette.surfaceBright,
        surfaceContainerLowestDark=darkPalette.surfaceContainerLowest,
        surfaceContainerLowDark=darkPalette.surfaceContainerLow,
        surfaceContainerDark=darkPalette.surfaceContainer,
        surfaceContainerHighDark=darkPalette.surfaceContainerHigh,
        surfaceContainerHighestDark=darkPalette.surfaceContainerHighest
    )

    @Transient private var lightColorSchemeTemp:ColorScheme?=null
    @Transient private var darkColorSchemeTemp:ColorScheme?=null

    override val lightScheme:ColorScheme get() {
        if (lightColorSchemeTemp==null)
            lightColorSchemeTemp= ColorScheme(
                primary = primaryLight,
                onPrimary = onPrimaryLight,
                primaryContainer = primaryContainerLight,
                onPrimaryContainer = onPrimaryContainerLight,
                secondary = secondaryLight,
                onSecondary = onSecondaryLight,
                secondaryContainer = secondaryContainerLight,
                onSecondaryContainer = onSecondaryContainerLight,
                tertiary = tertiaryLight,
                onTertiary = onTertiaryLight,
                tertiaryContainer = tertiaryContainerLight,
                onTertiaryContainer = onTertiaryContainerLight,
                error = errorLight,
                onError = onErrorLight,
                errorContainer = errorContainerLight,
                onErrorContainer = onErrorContainerLight,
                background = backgroundLight,
                onBackground = onBackgroundLight,
                surface = surfaceLight,
                onSurface = onSurfaceLight,
                surfaceVariant = surfaceVariantLight,
                onSurfaceVariant = onSurfaceVariantLight,
                outline = outlineLight,
                outlineVariant = outlineVariantLight,
                scrim = scrimLight,
                inverseSurface = inverseSurfaceLight,
                inverseOnSurface = inverseOnSurfaceLight,
                inversePrimary = inversePrimaryLight,
                surfaceDim = surfaceDimLight,
                surfaceBright = surfaceBrightLight,
                surfaceContainerLowest = surfaceContainerLowestLight,
                surfaceContainerLow = surfaceContainerLowLight,
                surfaceContainer = surfaceContainerLight,
                surfaceContainerHigh = surfaceContainerHighLight,
                surfaceContainerHighest = surfaceContainerHighestLight,
                surfaceTint = primaryLight
            )
        return lightColorSchemeTemp!!
    }

    override val darkScheme:ColorScheme get() {
        if (darkColorSchemeTemp==null)
            darkColorSchemeTemp= ColorScheme(
                primary = primaryDark,
                onPrimary = onPrimaryDark,
                primaryContainer = primaryContainerDark,
                onPrimaryContainer = onPrimaryContainerDark,
                secondary = secondaryDark,
                onSecondary = onSecondaryDark,
                secondaryContainer = secondaryContainerDark,
                onSecondaryContainer = onSecondaryContainerDark,
                tertiary = tertiaryDark,
                onTertiary = onTertiaryDark,
                tertiaryContainer = tertiaryContainerDark,
                onTertiaryContainer = onTertiaryContainerDark,
                error = errorDark,
                onError = onErrorDark,
                errorContainer = errorContainerDark,
                onErrorContainer = onErrorContainerDark,
                background = backgroundDark,
                onBackground = onBackgroundDark,
                surface = surfaceDark,
                onSurface = onSurfaceDark,
                surfaceVariant = surfaceVariantDark,
                onSurfaceVariant = onSurfaceVariantDark,
                outline = outlineDark,
                outlineVariant = outlineVariantDark,
                scrim = scrimDark,
                inverseSurface = inverseSurfaceDark,
                inverseOnSurface = inverseOnSurfaceDark,
                inversePrimary = inversePrimaryDark,
                surfaceDim = surfaceDimDark,
                surfaceBright = surfaceBrightDark,
                surfaceContainerLowest = surfaceContainerLowestDark,
                surfaceContainerLow = surfaceContainerLowDark,
                surfaceContainer = surfaceContainerDark,
                surfaceContainerHigh = surfaceContainerHighDark,
                surfaceContainerHighest = surfaceContainerHighestDark,
                surfaceTint = primaryDark
            )
        return darkColorSchemeTemp!!
    }
}

fun ColorScheme.toLegacy():ColorScheme=
    ColorScheme(
        primary,
        onPrimary,
        primaryContainer.containerGrey(),
        onPrimaryContainer,
        inversePrimary,
        secondary,
        onSecondary,
        secondaryContainer.containerGrey(),
        onSecondaryContainer,
        tertiary,
        onTertiary,
        tertiaryContainer.containerGrey(),
        onTertiaryContainer,
        background.containerGrey(),
        onBackground,
        surface.containerGrey(),
        onSurface,
        surfaceVariant.containerGrey(),
        onSurfaceVariant,
        surfaceTint.containerGrey(),
        inverseSurface.containerGrey(),
        inverseOnSurface,
        error,
        onError,
        errorContainer.containerGrey(),
        onErrorContainer,
        outline,
        outlineVariant,
        scrim.containerGrey(),
        surfaceBright.containerGrey(),
        surfaceContainer.containerGrey(),
        surfaceContainerHigh.containerGrey(),
        surfaceContainerHighest.containerGrey(),
        surfaceContainerLow.containerGrey(),
        surfaceContainerLowest.containerGrey(),
        surfaceDim.containerGrey()
    )

fun Color.containerGrey():Color{
    val rgbAvr=(red+green+blue)/3f
    return copy(alpha,rgbAvr,rgbAvr,rgbAvr)
}